﻿using ErrorOr;
using Gym.Application.Common.Interfaces;
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Gym.Application.Reservations.Commands.CreateReservation
{
    public class CreateReservationCommandHandler : IRequestHandler<CreateReservationCommand, ErrorOr<Success>>
    {
        private readonly ISessionsRepository _sessionsRepository;
        private readonly IParticipantsRepository _participantsRepository;

        public CreateReservationCommandHandler(ISessionsRepository sessionsRepository, IParticipantsRepository participantsRepository)
        {
            _sessionsRepository = sessionsRepository;
            _participantsRepository = participantsRepository;
        }

        public async Task<ErrorOr<Success>> Handle(CreateReservationCommand request, CancellationToken cancellationToken)
        {
            var session = await _sessionsRepository.GetByIdAsync(request.SessionId);
            if (session is null)
            {
                return Error.NotFound(description: "没有找到该课程信息");
            }
            if (session.HasReservationForParticipant(request.ParticipantId))
            {
                return Error.Conflict(description: "该用户已预约该课程");
            }

            var participant = await _participantsRepository.GetByIdAsync(request.ParticipantId);
            if (participant is null)
            {
                return Error.NotFound(description: "没有找到该用户信息");
            }

            if (participant.HasReservationForSession(session.Id))
            {
                return Error.Unexpected(description: "该用户已预约该课程");
            }

            if (!participant.IsTimeSlotFree(session.Date, session.Time))
            {
                return Error.Conflict(description: "该用户在该时间段内已预约其他课程");
            }

            var reserveSpotResult = session.ReserveSpot(participant);
            if (reserveSpotResult.IsError)
            {
                return reserveSpotResult.Errors;
            }

            await _sessionsRepository.UpdateAsync(session);
            return Result.Success;
        }
    }
}
